<script setup lang="ts">
import {Map, View} from 'ol'
import {computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch} from "vue"
import {createLayers} from "@/utils/gps/locaTool";
import mapType from "@/utils/gps/mapType";
import {readTransform} from "@/utils/gps/gpsTrans";
import {useGetTrackPosApi} from "@/api/gps/gps";
import { Point } from 'ol/geom'
import LineString from 'ol/geom/LineString'
import sourceVector from 'ol/source/Vector'
import Feature from 'ol/Feature'
import layerVector from 'ol/layer/Vector'
import { Circle, Fill, Stroke, Style, Icon, Text } from 'ol/style'
import start_IconPng from "@/assets/image/start_icon.png"
import end_IconPng from "@/assets/image/end_icon.png"
import car_bluePng from "@/assets/image/car_blue.png"
import stopCar from "@/assets/image/stop_icon.png"
import {ElMessage, ElCard, ElButton, ElProgress, ElInputNumber, ElDatePicker, ElLoading} from "element-plus"
import { VideoPlay, Refresh, VideoPause, DArrowRight, DArrowLeft } from "@element-plus/icons-vue"
import {IsPtInPoly} from "@/utils/gps/inside";

const props = defineProps({
  plateNum: {
    type: String,
    required: true
  }
})

let demo: any = null
const loading = ref(true)
const dateRange = ref(["2023-11-01", "2023-12-31"])
const record = reactive<{position: any[], travelPath: any[], stopPosition: any[]}>({
  position: [],
  travelPath: [],
  stopPosition: []
})

const openMap = ref<Map>()
const vectorLayer = ref<layerVector<any>>()
const iconLayer = ref()
const carSource = ref()
let carFeature: Feature
// 播放速率
const playSpeed = ref(100)
// 进度
const percentage = ref(0)
const currentPosition = ref<{[key: string]: any}>()
const polylinePath = ref([])
let stepInterval: any = null
const currentStep = ref(0)
const isPlay = ref(false)
const speed = ref(0)
watch(()=> loading.value, (value)=>{
  if(value) nextTick(()=>{
    demo = ElLoading.service({ target: ".demo", text: "生成数据中...", background: "rgba(255,255,255,0.7)"})
  })
  else demo?.close()
}, {
  immediate: true
})
const currentPage = computed(()=>{
  return (record.position.length > 0? currentStep.value + 1 : 0) + " / " + record.position.length
})

onMounted(()=>{
  init()
})
onBeforeUnmount(()=>{
  clearInterval(stepInterval)
})
function init(){
  if(!props.plateNum) return
  initMap(readTransform(31.503466, 104.78875))
  getData()
}

/**
 * 重置数据
 */
function handleReset(){
  record.position = []

}
/**
 * 获取数据
 */
function getData(){
  loading.value = true
  useGetTrackPosApi({
    plateNo: "13306526101",
    startTime: dateRange.value[0],
    endTime: dateRange.value[1],
    withStop: true,
    withPos: true,
    withTrip: false
  }).then(res=>{
    const {positions, stops} = res.data
    record.position = positions
    if(stops?.length){
      record.stopPosition = stops.map((item: any)=>{
        return {
          ...readTransform(item.longitude, item.latitude),
          time: timeFormat(item.duration)
        }
      })
    }
    if(positions?.length){
      currentPosition.value = positions[0]
      record.travelPath = positions.map((item: any) => readTransform(item.longitude, item.latitude))
      if(vectorLayer.value) openMap.value?.removeLayer(vectorLayer.value)
      if(iconLayer.value) openMap.value?.removeLayer(iconLayer.value)
      trajectoryPath(record.travelPath)
    }else {

    }
  }, error =>{
    ElMessage.error("数据异常，如有疑问请联系管理员")
  }).finally(()=>{
    loading.value = false
  })
}

/**
 * 日期转换
 * @param timeLong
 */
function timeFormat(timeLong: number) {
  const timeStamp = Math.floor(timeLong / 1000)
  const days = Math.floor(timeStamp / (24 * 3600))
  const yu = timeStamp % (24 * 3600)
  const hours = Math.floor(yu / 3600)
  const yu2 = yu % 3600
  const minutes = Math.floor(yu2 / 60)
  const seconds = yu2 % 60
  return ((days === 0) ? '' : (days + '天'))
      + ((hours === 0) ? '' : (hours + '小时'))
      + ((minutes === 0) ? '' : (minutes + '分'))
      + ((seconds === 0) ? '-' : (seconds + '秒'))
}

/**
 * 初始化地图
 * @param options
 */
function initMap(options: number[]){
  openMap.value = new Map({
    target: 'map-fence-s',
    layers: createLayers(mapType),
    view: new View({
      projection: 'EPSG:4326',
      center: [104.07102, 30.666756],
      // 地图缩放最小级别
      minZoom: 5,
      maxZoom: 20,
      // 地图缩放级别
      zoom: 12,
    }),
  })
}

/**
 * 画轨迹
 * @param e
 */
function trajectoryPath(e: any[]){
  const polyline = e
  // 实例化图层
  let geometry = new LineString(polyline)
  let source = new sourceVector()
  // 绘制轨迹
  let LineFeature = new Feature(geometry)
  source.addFeature(LineFeature)
  vectorLayer.value = new layerVector({
    source,
    style: new Style({
      fill: new Fill({
        color: 'rgba(255, 255, 255, 0.6)',
      }),
      stroke: new Stroke({
        color: 'rgba(0,153,255, 0.6)',
        width: 8,
      }),
      image: new Circle({
        radius: 7,
        fill: new Fill({
          color: '#0099FF',
        })
      })
    })
  })
  openMap.value?.addLayer(vectorLayer.value)
  setMark(polyline)
}

/**
 * 画Marker点
 * @param e
 */
function setMark(e: any[]){
  let markers: any[] = [
    {
      po: e[0],
      key: start_IconPng,
      name: 'start',
    },
    {
      po: e[e.length - 1],
      key: end_IconPng,
      name: 'end',
    },
  ]
  if(record.stopPosition.length > 0){
    markers.push(...record.stopPosition.map((item: any) => {
      return {
        po: [item[0], item[1]],
        key: stopCar,
        name: 'stop',
        time: item.time,
      }
    }))
  }
  let isIcon: any[] = []
  markers.forEach((item: any) =>{
    // 创建图标特性
    let iconFeature = new Feature({
      geometry: new Point(item.po),
      name: item.name,
    })
    // 创建图标样式
    iconFeature.setStyle(new Style({
      image: new Icon({
        // 定义图标锚点
        anchor: [12, 0.5],
        anchorOrigin: 'bottom-left',
        anchorXUnits: 'pixels',
        anchorYUnits: 'pixels',
        src: item.key
      }),
      text: item.name === "stop"? new Text({
        font: '13px sans-serif',
        offsetX: 0,
        offsetY: -50,
        textAlign: 'center',
        textBaseline: 'middle',
        text: `停留时间：${item.time}`,
        backgroundFill: new Fill({
          color: 'rgba(128,134,149, 0.8)',
        }),
        fill: new Fill({
          color: '#fff',
        }),
        padding: [4, 5, 4, 5],
      }): undefined
    }))
    isIcon.push(iconFeature)
  })
  let vectorSource = new sourceVector({
    features: isIcon,
  })
  // 图标添加进矢量容器
  carSource.value = vectorSource
  // 创建矢量图层
  iconLayer.value = new layerVector({
    source: vectorSource,
  })
  openMap.value?.addLayer(iconLayer.value)
  // 绘制车表
  timeMarker([record.position[0].longitude, record.position[0].latitude], 0, false)
  // 定位地图总心
  openMap.value?.getView().setCenter(e[0])
  console.log("end")
}

/**
 * 遍历
 * @param v
 * @param rotation
 * @param status
 */
function timeMarker(v: any[], rotation: number, status: boolean){
  if(status) carSource.value.removeFeature(carFeature)
  carFeature = new Feature({
    geometry: new Point(readTransform(v[0], v[1])),
  })
  carFeature.setStyle(new Style({
    image: new Icon({
      // 定义图标锚点
      anchor: [10, 18],
      anchorOrigin: 'bottom-left',
      anchorXUnits: 'pixels',
      anchorYUnits: 'pixels',
      rotation: (Math.PI / 180) * (rotation % 360),
      src: car_bluePng,
    }),
  }))
  carSource.value.addFeature(carFeature)
}

/**
 * 判断小车是否在可视范围内
 * @param lat
 * @param lng
 */
function isInside(lat: number, lng: number){
  let isArr: any = openMap.value?.getView().calculateExtent(openMap.value?.getSize())
  if(!IsPtInPoly(lat, lng, [
    {longitude: isArr[2], latitude: isArr[1]},
    {longitude: isArr[0], latitude: isArr[1]},
    {longitude: isArr[0], latitude: isArr[3]},
    {longitude: isArr[2], latitude: isArr[3]}
  ])) openMap.value?.getView().setCenter([lng, lat])
}

/**
 * 开始播放
 */
function handlePlay(){
  if(record.position.length === 0) return ElMessage.warning("无法播放")
  stepInterval = setInterval(()=>{
    if(currentStep.value < record.position.length - 1){
      isPlay.value = true
      currentStep.value++
      currentPosition.value = record.position[currentStep.value]
      timeMarker([currentPosition.value?.longitude, currentPosition.value?.latitude], currentPosition.value?.course, true)
      isInside(currentPosition.value?.latitude, currentPosition.value?.longitude)
      speed.value = record.position[currentStep.value].speed
      percentage.value = parseFloat((currentStep.value / record.position.length * 100).toFixed(1))
    }else {
      percentage.value = 100
      handlePause()
    }
  }, playSpeed.value)
}

/**
 * 暂停播放
 */
function handlePause(){
  isPlay.value = false
  clearInterval(stepInterval)
}

/**
 * 重置播放
 */
function handleRefresh(){
  currentStep.value = 0
  percentage.value = 0
  currentPosition.value = record.position[0]
  polylinePath.value.splice(0, polylinePath.value.length)
}

/**
 * 上一步
 */
function handlePrev(){
  if(currentStep.value > 0 && currentStep.value <= record.position.length) currentStep.value --
  polylinePath.value.splice(currentStep.value, polylinePath.value.length)
  adjust()
}

/**
 * 下一步
 */
function handleNext(){
  if(currentStep.value < record.position.length) currentStep.value ++
  adjust()
}
function adjust(){
  const start = record.position[currentStep.value]
  currentPosition.value = start
  // 获取速度表
  speed.value = start?.speed
  // 获取百分比
  percentage.value = parseFloat((currentStep.value / record.position.length * 100).toFixed(1))
  const rotation = start?.course
  timeMarker([start.longitude, start.latitude], rotation, true)
}
</script>

<template>
  <div style="position: relative" class="demo">
    <div id="map-fence-s" class="map-fence"></div>
    <ElCard class="tool-window" :style="{width: '400px', position: 'absolute', bottom: '-10px',
      right: '-25px', background: 'rgba(255,255,255,0.7)', border: 'none'}"
      :body-style="{}">
      <ElDatePicker v-model="dateRange" type="daterange"
                    value-format="YYYY-MM-DD">
      </ElDatePicker>
      <div style="margin: 20px 0;">
        播放速度
        <ElInputNumber v-model="playSpeed" :precision="0" :min="100" :max="5000" step-strictly :step="100" style="width: 150px;"></ElInputNumber>
        毫秒
      </div>
      <ElProgress :text-inside="true" :stroke-width="15" :percentage="percentage"></ElProgress>
      <div style="margin: 10px 0">轨迹时间：{{ currentPosition?.deviceTime }} </div>
      <div style="margin-bottom: 10px;">运动速度：{{ (speed * 1.852).toFixed(2) }} Km/h</div>
      <div class="control">
        <ElButton v-if="!isPlay" type="primary" :icon="VideoPlay" @click="handlePlay"></ElButton>
        <ElButton v-else type="primary" :icon="VideoPause" @click="handlePause"></ElButton>
        <ElButton type="danger" :icon="Refresh" @click="handleRefresh"></ElButton>
        <el-button type="success" class="button" :disabled="currentStep === 0" :icon="DArrowLeft" @click="handlePrev"></el-button>
        <span class="pageNum">{{currentPage}}</span>
        <el-button type="success" class="button"
                   :disabled="currentStep === record.position.length - 1 || record.position.length === 0"
                   :icon="DArrowRight" @click="handleNext"></el-button>
      </div>
    </ElCard>
  </div>
</template>

<style scoped lang="scss">
  .map-fence{
    width: 1200px;
    height: 700px;
  }
  .control{
    display: flex;
    margin-top: 20px;
  }
  .pageNum{
    display: inline-block;
    font-size: 20px;
    transform: translateY(5px);
    margin: 0 5px;
  }
</style>
